package com.example.yinhangmiaosha.service;

import com.example.yinhangmiaosha.domain.Stock;
import com.example.yinhangmiaosha.domain.User;
import com.example.yinhangmiaosha.mapper.UserMapper;
import com.example.yinhangmiaosha.util.CacheKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

    private static final String SALT = "randomString";
    private static final int ALLOW_COUNT = 5;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StockService stockService;

    @Override
    public String getVerifyHash(Integer sid, Integer userId) throws Exception {

        // 验证是否在抢购时间内
        LOGGER.info("请自行验证是否在抢购时间内");


        // 检查用户合法性
        User user = userMapper.selectByPrimaryKey(userId.longValue());
        if (user == null) {
            throw new Exception("用户不存在");
        }
        LOGGER.info("用户信息：[{}]", user.toString());

        // 检查商品合法性
        Stock stock = stockService.getStockById(sid);
        if (stock == null) {
            throw new Exception("商品不存在");
        }
        LOGGER.info("商品信息：[{}]", stock.toString());

        // 生成hash
        String verify = SALT + sid + userId;
        String verifyHash = DigestUtils.md5DigestAsHex(verify.getBytes());

        // 将hash和用户商品信息存入redis
        String hashKey = CacheKey.HASH_KEY.getKey() + "_" + sid + "_" + userId;
        stringRedisTemplate.opsForValue().set(hashKey, verifyHash, 3600, TimeUnit.SECONDS);
        LOGGER.info("Redis写入：[{}] [{}]", hashKey, verifyHash);
        return verifyHash;
    }

    /**
     * 5s内，单个用户请求次数不得超过5次
     * @param userId
     * @return
     * @throws Exception
     */
    @Override
    public int addUserCount(Integer userId) throws Exception {
        String limitKey = CacheKey.LIMIT_KEY.getKey() + "_" + userId;
        stringRedisTemplate.opsForValue().setIfAbsent(limitKey, "0", 5, TimeUnit.SECONDS);
        Long limit = stringRedisTemplate.opsForValue().increment(limitKey);
        return Integer.parseInt(String.valueOf(limit));
    }

    @Override
    public boolean getUserIsBanned(Integer userId) {
        String limitKey = CacheKey.LIMIT_KEY.getKey() + "_" + userId;
        stringRedisTemplate.opsForValue().setIfAbsent(limitKey, "0", 5, TimeUnit.SECONDS);
        String limitNum = stringRedisTemplate.opsForValue().get(limitKey);
        if (limitNum == null) {
            LOGGER.error("该用户没有访问申请验证值记录，疑似异常");
            return true;
        }
        return Integer.parseInt(limitNum) >= ALLOW_COUNT;
    }

    @Override
    public User getUserByName(String userName) {
        return userMapper.getUserByName(userName);
    }

    @Override
    public boolean getUserIsPermitted(Integer userId) {
        Boolean isPermitted = getUserIsPermittedByCache(userId);
        if (isPermitted == null) {
            return getUserIsPermittedByCheck(userId);
        }
        return isPermitted;
    }

    @Override
    public Boolean getUserIsPermittedByCache(Integer userId) {
        String permissionKey = CacheKey.USER_PERMISSION.getKey() + "_" + userId;
        String permission = stringRedisTemplate.opsForValue().get(permissionKey);
        Boolean isPermitted = Boolean.parseBoolean(permission);
        return isPermitted;
    }

    @Override
    public boolean getUserIsPermittedByCheck(Integer userId) {
        // 初筛用户，并将结果写入缓存
        User user = userMapper.selectByPrimaryKey(userId.longValue());
        boolean isPermitted =
                getAgeIsPermitted(user) && getCreditIsPermitted(user)
                        && getJobIsPermitted(user) && getRecordIsPermitted(user);
        String permissionKey = CacheKey.USER_PERMISSION.getKey() + "_" + userId;
        stringRedisTemplate.opsForValue().set(permissionKey, String.valueOf(isPermitted));
        String permissionTimeKey = CacheKey.USER_PERMISSION_TIME.getKey() + "_" + userId;
        Date nowTime = new Date();
        stringRedisTemplate.opsForValue().set(permissionTimeKey, nowTime.toString());
        return false;
    }

    @Override
    public boolean getAgeIsPermitted(User user) {
        return false;
    }

    @Override
    public boolean getCreditIsPermitted(User user) {
        return false;
    }

    @Override
    public boolean getJobIsPermitted(User user) {
        return false;
    }

    @Override
    public boolean getRecordIsPermitted(User user) {
        return false;
    }
}
